/**
 * 
 */
package org.mspring.mlog.service.impl;

import java.util.Date;
import java.util.List;

import net.sf.ehcache.Element;

import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.mspring.mlog.entity.Attachment;
import org.mspring.mlog.entity.News;
import org.mspring.mlog.service.AttachmentService;
import org.mspring.mlog.service.NewsService;
import org.mspring.mlog.web.security.SecurityUtils;
import org.mspring.platform.cache.service.CacheService;
import org.mspring.platform.cache.service.DefaultCacheService;
import org.mspring.platform.persistence.hibernate.BaseHibernateDao;
import org.mspring.platform.persistence.hibernate.common.EnhancedRule;
import org.mspring.platform.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 
 * @author Gao Youbo
 * @since 2013年6月28日
 */
@Service
@Transactional
public class NewsServiceImpl extends BaseHibernateDao<News, Long> implements NewsService {

    @Autowired
    private AttachmentService attachmentService;
    @Autowired
    private DefaultCacheService defaultCacheService;

    @Override
    public News save(News news) {
        // TODO Auto-generated method stub
        if (news.getCreateTime() == null) {
            news.setCreateTime(new Date());
        }
        if (news.getAuthor() == null) {
            news.setAuthor(SecurityUtils.getCurrentUser());
        }
        if (StringUtils.isBlank(news.getStatus())) {
            news.setStatus(News.Status.PUBLISH);
        }
        news.setViews(new Long(0));
        news.setComments(new Long(0));
        news = super.save(news);
        return news;
    }

    @Override
    public News merge(News news) {
        // TODO Auto-generated method stub
        if (news.getCreateTime() == null) {
            news.setCreateTime(new Date());
        }
        if (news.getAuthor() == null) {
            news.setAuthor(SecurityUtils.getCurrentUser());
        }
        if (StringUtils.isBlank(news.getStatus())) {
            news.setStatus(News.Status.PUBLISH);
        }
        return super.merge(news);
    }

    @Override
    public void update(News news) {
        // TODO Auto-generated method stub
        if (StringUtils.isBlank(news.getStatus())) {
            news.setStatus(News.Status.PUBLISH);
        }
        super.update(news);
    }

    @Override
    public void remove(News news) {
        // TODO Auto-generated method stub
        if (news == null || news.getId() == null) {
            return;
        }
        remove(news.getId());
    }

    @Override
    public void remove(Long... ids) {
        // TODO Auto-generated method stub
        for (Long id : ids) {
            if (id == null) {
                return;
            }

            // 删除对应的附件
            List<Attachment> attachments = attachmentService.findAttachments(id.toString(), Attachment.AttachFromType.FROM_NEWS);
            for (Attachment attachment : attachments) {
                attachmentService.deleteAttachment(attachment.getId());
            }
            super.remove(id);
        }
    }

    @Override
    public List<News> recent(int num) {
        // TODO Auto-generated method stub
        EnhancedRule rule = new EnhancedRule();
        rule.addOrder(Order.desc("createTime"));
        rule.add(Restrictions.eq("status", News.Status.PUBLISH));
        rule.setPageSize(num);
        return list(rule);
    }

    @Override
    public List<News> hot(int num, Date start, Date end) {
        // TODO Auto-generated method stub
        EnhancedRule rule = new EnhancedRule();
        rule.addOrder(Order.desc("views"));
        rule.add(Restrictions.eq("status", News.Status.PUBLISH));
        rule.setPageSize(num);
        if (start != null) {
            rule.add(Restrictions.ge("createTime", start));
        }
        if (end != null) {
            rule.add(Restrictions.le("createTime", end));
        }
        return list(rule);
    }

    /**
     * 当新闻点击量累积到多少时进行一次数据持久化
     */
    public static final Integer UPDATE_VIEWS_BATCH = 10;

    /**
     * 临时缓存新闻点击率的cachekey前缀
     */
    public static final String NEWS_VIEWS_UPDATE_CACHE = "NEWS_VIEWS_UPDATE_CACHE_";

    @Override
    public void updateViews(Long id) {
        // TODO Auto-generated method stub
        Long views = Long.valueOf(1);
        Element ele = defaultCacheService.getCache().get(NEWS_VIEWS_UPDATE_CACHE + id);
        if (ele != null && ele.getValue() != null) {
            views = Long.valueOf(ele.getValue().toString()) + 1;
        }

        // long one_hour = CacheService.ONE_HOUR * 1000; // 一小时的毫秒数
        // // 如果该新闻缓存中保存的点击率大于UPDATE_VIEWS_BATCH，或者缓存时间超过一个小时，那么将缓存数据更新到数据库一次
        // if (views >= UPDATE_VIEWS_BATCH || (ele != null &&
        // System.currentTimeMillis() - ele.getCreationTime() > one_hour)) {
        // executeUpdate("update NewsExt ext set ext.views = ext.views + ? where ext.newsId = ?",
        // views, newsId);
        // defaultCacheService.deleteDefaultCacheValue(NEWS_VIEWS_UPDATE_CACHE +
        // newsId);
        // } else {
        // defaultCacheService.updateDefaultCacheValue(NEWS_VIEWS_UPDATE_CACHE +
        // newsId, views, CacheService.ONE_DAY);
        // }

        long interval = 10 * 60 * 1000; // 10分钟
        if (ele != null && System.currentTimeMillis() - ele.getCreationTime() > interval) {
            executeUpdate("update News news set news.views = news.views + ? where news.id = ?", views, id);
            defaultCacheService.deleteDefaultCacheValue(NEWS_VIEWS_UPDATE_CACHE + id);
        } else {
            defaultCacheService.updateDefaultCacheValue(NEWS_VIEWS_UPDATE_CACHE + id, views, CacheService.ONE_DAY);
        }
    }
}
